﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using AirlineBooking.Models.DTO;

namespace AirlineBooking.Models
{
    public class RouteModel
    {
        public List<List<string>> findRoutes(AirLineDBModelEntities db, AirPort dep, AirPort des)
        {
            List<List<string>> res = new List<List<string>>();

            if (dep == null || des == null)
            {
                return null;
            }
            if (des.Code == dep.Code)
            {
                return null;
            }
            List<string> nearDep = db.FindAdjacentAirport(dep.Code).ToList();
            if (nearDep.Contains(des.Code))
            {
                //Có đường bay trực tiếp
                res.Add(new List<string>() { dep.Code, des.Code });
                nearDep.Remove(des.Code);
            }
            List<string> nearDes = db.FindAdjacentAirport(des.Code).ToList();
            foreach (string transit in nearDep)
            {
                List<string> nexts = db.FindAdjacentAirport(transit).ToList();
                foreach (string transit2 in nexts)
                {
                    if (transit2 == des.Code)
                    {
                        //Các đường bay có 1 transit
                        res.Add(new List<string>() { dep.Code, transit, des.Code });
                    }
                    else if (nearDes.Contains(transit2) && transit2 != dep.Code)
                    {
                        res.Add(new List<string>() { dep.Code, transit, transit2, des.Code });
                    }
                }
            }

            return res;
        }

        public List<DTOIntineraryOptions> findIntineraryOptions(string DepartureAirportCode, string DestinationAirportCode, DateTime departDate, int adult, int child, int infant)
        {
            int NumberOfPassenger = adult + child;
            AirportModel airportModel = new AirportModel();
            List<DTOIntineraryOptions> result = new List<DTOIntineraryOptions>();
            using (AirLineDBModelEntities db = new AirLineDBModelEntities())
            {
                AirPort dep = db.AirPorts.FirstOrDefault(i => i.Code == DepartureAirportCode);
                AirPort des = db.AirPorts.FirstOrDefault(i => i.Code == DestinationAirportCode);
                if (dep == null || des == null)
                {
                    return result;
                }

                List<List<string>> options = findRoutes(db, dep, des);
                foreach (List<string> route in options)
                {

                    DTOAirport departureAirport = new DTOAirport() { Code = dep.Code, Name = dep.Name, ServiceFee = dep.ServiceFee ?? 0 };
                    DTOAirport destinationAirport = new DTOAirport() { Code = des.Code, Name = des.Name, ServiceFee = des.ServiceFee ?? 0 };
                    Dictionary<DTOClassType, DTOIntineraryOptions> intineraries = new Dictionary<DTOClassType, DTOIntineraryOptions>();
                    foreach (DTOClassType classType in DTOClassType.AllTypes)
                    {
                        DTOIntineraryOptions inti = new DTOIntineraryOptions() { Departure = departureAirport, Destination = destinationAirport, ClassType = classType };
                        inti.Connections = new List<DTOFlightOptions>();
                        intineraries.Add(classType, inti);
                    }

                    for (int i = 0; i < route.Count - 1; i++)
                    {
                        string a1 = route[i];
                        string a2 = route[i + 1];
                        DateTime lowerDate = departDate.Date;
                        DateTime upperDate = lowerDate.AddDays(1 + i);
                        int CancelledStatus = DTOIntineraryStatus.Cancelled.Id;
                        var query = db.SeatRegions.Where(sg => ((sg.Flight1.Segment1.Departure == a1 && sg.Flight1.Segment1.Destination == a2)
                                                                || (sg.Flight1.Segment1.Departure == a2 && sg.Flight1.Segment1.Destination == a1))
                                                                && sg.Flight1.ScheduleDeparture >= lowerDate && sg.Flight1.ScheduleArrival < upperDate
                                                                && sg.NumberOfSeat - sg.Tickets.Where(t => t.Intinerary1.Status != CancelledStatus).Count() > NumberOfPassenger
                                                                )
                                                                .Select(sg => new { FlightCode = sg.Flight1.Code, Operator = sg.Flight1.Operator1.Name, ArrivalTime = sg.Flight1.ScheduleArrival, DepatureTime = sg.Flight1.ScheduleDeparture, ClassType = sg.ClassType, SegmentId = sg.Flight1.Segment, OperatorCode = sg.Flight1.Operator });

                        DTOAirport dtoA1 = airportModel.GetAirport(a1);
                        DTOAirport dtoA2 = airportModel.GetAirport(a2);
                        Dictionary<DTOClassType, DTOFlightOptions> flOptions = new Dictionary<DTOClassType, DTOFlightOptions>();
                        foreach (DTOClassType classType in DTOClassType.AllTypes)
                        {
                            DTOFlightOptions flOpt = new DTOFlightOptions();
                            flOpt.Departure = dtoA1;
                            flOpt.Destination = dtoA2;
                            flOpt.Flights = new List<DTOFlight>();
                            flOptions.Add(classType, flOpt);
                        }

                        foreach (var flight in query)
                        {
                            DTOFlight dto = new DTOFlight();
                            dto.FlightCode = flight.FlightCode;
                            dto.Operator = flight.Operator;
                            dto.ArrivalTime = flight.ArrivalTime;
                            dto.DepatureTime = flight.DepatureTime;
                            foreach (DTOClassType item in DTOClassType.AllTypes)
                            {
                                if (flight.ClassType == item.Id)
                                {
                                    dto.ClassType = item;
                                    break;
                                }
                            }
                            var tariffQuery = db.Tariffs.Where(t => t.StartDate <= dto.DepatureTime && t.EndDate >= dto.DepatureTime && t.Operator == flight.OperatorCode && t.Segment == flight.SegmentId && t.ClassType == flight.ClassType);
                            decimal price = 0;
                            foreach (Tariff tariff in tariffQuery)
                            {
                                string ptype = tariff.PassengerType1.Name;
                                if (ptype == "Adult")
                                {
                                    price += adult * tariff.BasePrice;
                                }
                                else if (ptype == "Children")
                                {
                                    price += child * tariff.BasePrice;
                                } else {
                                    price += infant * tariff.BasePrice;
                                }
                            }
                            dto.Price = price;
                            if (flOptions.ContainsKey(dto.ClassType))
                            {
                                flOptions[dto.ClassType].Flights.Add(dto);
                            }
                        }
                        foreach (DTOIntineraryOptions item in intineraries.Values)
                        {
                            item.Connections.Add(flOptions[item.ClassType]);
                        }
                    }
                    foreach (DTOIntineraryOptions item in intineraries.Values)
                    {
                        bool OK = true;
                        foreach (DTOFlightOptions con in item.Connections)
                        {
                            if (con.Flights.Count == 0)
                            {
                                OK = false;
                                break;
                            }
                        }
                        if (OK)
                        {
                            result.Add(item);
                        }
                    }
                }
            }
            return result;
        }
    }
}